# Copyright 2011 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Various datastore models"""

import logging
import pickle

from google.appengine.ext import db


class BlobFile(db.Model):
    """A file-like entity.

    Call class method Open() to create/update a blob file.
    """
    # Contents of the file.
    data = db.BlobProperty()

    __KEYNAME_PREFIX = u'key:'

    def filename(self):
        """Gets filename.

        Returns:
          unicode string representing a filename.

        Raises:
          ValueError when the filename is not recoverable.
        """
        if self.key().name().startswith(BlobFile.__KEYNAME_PREFIX):
            return self.key().name()[len(BlobFile.__KEYNAME_PREFIX):]
        else:
            logging.fatal('Invalid key_name: %s' % self.key().name())
            raise ValueError


    @classmethod
    def __GenerateKeynameFromFilename(cls, filename):
        """Generates keyname from "filename".

        Arguments:
          filename: unicode string representing a filename.

        Returns:
          unicode string representing a keyname.

        Raises:
          ValueError when the filename is not unicode.
        """
        if not isinstance(filename, unicode):
            logging.fatal('Invalid filename: %s' % filename)
            raise ValueError

        return BlobFile.__KEYNAME_PREFIX + filename


    @classmethod
    def Open(cls, filename):
        """Opens a file.

        Arguments:
          filename: unicode string representing a filename.

        Returns:
          BlobFile object.

        Raises:
          ValueError when the filename is not unicode.
        """
        if not isinstance(filename, unicode):
            logging.fatal('Invalid filename: %s' % filename)
            raise ValueError

        keyname = BlobFile.__GenerateKeynameFromFilename(filename)
        blobfile = BlobFile.get_by_key_name(keyname)
        if blobfile:
            return blobfile
        else:
            return BlobFile(key_name=keyname)


class BlobFileSet(db.Model):
    """Record to keep versioned BlobFiles.

    Use Open() to get/create a BlobFileSet and Sync() to write to Data Store.
    """
    version_filename_map_internal = db.BlobProperty()
    latest_version = db.StringProperty()

    __KEYNAME_PREFIX = u'key:'

    def __getattr__(self, name):
        if name == 'version_filename_map':
            if self.version_filename_map_internal:
                self.version_filename_map = pickle.loads(
                    self.version_filename_map_internal)
            else:
                self.version_filename_map = {}
            return self.version_filename_map
        else:
            raise AttributeError

    def Sync(self):
        self.version_filename_map_internal = pickle.dumps(
            self.version_filename_map)
        self.put()

    def fileset_name(self):
        if self.key().name().startswith(BlobFileSet.__KEYNAME_PREFIX):
            return self.key().name()[len(BlobFileSet.__KEYNAME_PREFIX):]
        else:
            logging.fatal('Invalid key_name: %s' % self.key().name())
            raise ValueError
        

    @classmethod
    def __GenerateKeynameFromFilesetName(cls, fileset_name):
        """Generates keyname from "fileset_name".

        Arguments:
          fileset_name: unicode string representing a fileset name.

        Returns:
          unicode string representing a keyname.

        Raises:
          ValueError when the filename is not unicode.
        """
        if not isinstance(fileset_name, unicode):
            logging.fatal('Invalid fileset_name: %s' % fileset_name)
            raise ValueError

        return BlobFileSet.__KEYNAME_PREFIX + fileset_name


    @classmethod
    def Open(cls, fileset_name):
        """Opens a file.

        Arguments:
          fileset_name: unicode string representing a fileset name.

        Returns:
          BlobFileSet object.

        Raises:
          ValueError when the fileset_name is not unicode.
        """
        if not isinstance(fileset_name, unicode):
            logging.fatal('Invalid fileset_name: %s' % fileset_name)
            raise ValueError

        keyname = BlobFileSet.__GenerateKeynameFromFilesetName(fileset_name)
        blobfile_set = BlobFileSet.get_by_key_name(keyname)
        if blobfile_set:
            return blobfile_set
        else:
            return BlobFileSet(key_name=keyname)


class AuthKeyRecord(db.Model):
    """When crating a new instance, clients are responsible to set key_name
    to the newly generated authkey."""
    user = db.UserProperty()
